Use case: conversion in multimode DMA

Description of usage

HAL1

HAL2

Start conversion in multimode DMA

Activate the ADC peripheral and start the conversion in multimode DMA using HAL_ADCEx_MultiModeStart_DMA(). Specify the buffer where the ADC data is stored and its length.

Activate the ADC peripheral and start the conversion using HAL_ADC_MM_Start().

Note

From this point, the ADC internal analog hardware is enabled, inducing a slight current consumption.

Start the conversion with a trigger using:

  • HAL_ADC_MM_REG_StartConv_DMA(): single DMA channel for all ADC instances.

  • HAL_ADC_MM_REG_StartConvM_DMA(): separate DMA channel for each ADC instance.

Note

The conversion trigger can be:

  • A software start: calls the function for each conversion.

  • From another peripheral (timer, for instance): calls the function once.

Calibration (optional)

  • Start calibration using HAL_ADCEx_Calibration_Start().

  • Get calibration value using HAL_ADCEx_Calibration_GetValue().

  • Set calibration value using HAL_ADCEx_Calibration_SetValue().

  • Calibrate each ADC using HAL_ADC_Calibrate() or all using HAL_ADC_MM_Calibrate().

  • Get calibration factor using HAL_ADC_GetCalibrationFactor().

  • Set calibration factor using HAL_ADC_SetCalibrationFactor().

DMA transfer complete callback

Implement the HAL_ADC_ConvCpltCallback() callback, which is called when the DMA transfer is complete. This callback function handles the completed conversion.

Implement the HAL_ADC_REG_DataTransferCpltCallback() callback, which is called when the DMA transfer is complete. This callback function handles the completed conversion.

DMA half-transfer callback

Implement the HAL_ADC_ConvHalfCpltCallback() callback, which is called when the DMA half-transfer is complete. This callback function handles the half-completed conversion.

Implement the HAL_ADC_REG_DataTransferHalfCallback() callback, which is called when the DMA half-transfer is complete. This callback function handles the half-completed conversion.

Retrieve conversion results

Use HAL_ADCEx_MultiModeGetValue() to retrieve the conversion results. This function can be called within the DMA transfer complete callback to get the combined result of the master and slave ADCs.

The conversion results are stored in the buffer specified in HAL_ADC_REG_StartConv_DMA(). Process the data in the DMA transfer complete and half-transfer complete callbacks.

Stop conversion

Stop potential ongoing conversions on the regular and injected groups and disable the ADC peripheral using HAL_ADCEx_MultiModeStop_DMA().

If the conversion trigger is not a software start (such as from another peripheral like a timer), stop the conversion using HAL_ADC_MM_REG_StopConv_DMA().

Stop the ADC using HAL_ADC_MM_Stop().

Loop for multiple iterations

N/A

Multiple iterations for starting and stopping conversions are possible.

Warning

If multiple conversions are required, do not fully stop the ADC using the HAL_ADC_Stop() function.

Sequence diagram

ADC data transfer in multimode DMA

@startuml

participant "User application\n(thread mode)" as appli
participant "User application\n(handler mode)" as appli_IRQ
participant "<font color=green><b>HAL ADC</b></font>" as ADC
participant "<font color=green><b>HAL DMA</b></font>" as DMA
participant "System HW interruption" as interruption

group#Bisque #Linen ADC operation
appli->ADC : HAL_ADCEx_MultiModeStart_DMA()
note right
From this point, the ADC internal analog hardware is
enabled (inducing a slight current consumption) and
conversion in DMA mode starts.
end note
return
appli->ADC : HAL_ADCEx_Calibration_Start()
return

ADC->ADC : Enable ADC selected interruptions\nEnable DMA request\nEnable ADC conversion trigger
interruption <[#purple]-x? : <font color=purple><b>DMA IRQ event\n(transfer complete)
interruption -> appli_IRQ : DMAx_IRQHandler()
activate appli_IRQ #DarkSalmon
appli_IRQ -> DMA : HAL_DMA_IRQHandler()
DMA -> DMA : Clear flag
DMA->ADC : Callback function pointer
ADC -> appli_IRQ: HAL_ADC_ConvCpltCallback()
appli_IRQ -> appli_IRQ : User appli processing
appli_IRQ -> interruption : (Return from ISR)
deactivate appli_IRQ

appli->ADC : HAL_ADCEx_MultiModeStop_DMA()
return
end

@enduml

Code snippet

HAL1

HAL2

uint32_t adcBuffer[2];

int main(void)
{
    // Add your Init and config code

    if (HAL_ADCEx_MultiModeStart_DMA(&hadc_master, (uint32_t*)adcBuffer, 2) != HAL_OK)
    {
        /* Start Error */
        Error_Handler();
    }

}

/* Error Handler */
void Error_Handler(void)
{
    while (1)
    {
       /* Stay in this loop in case of error */
    }
}

/* ADC conversion complete callback */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    if (hadc->Instance == ADC1)
    {
         /* Process the ADC conversion results stored in adcBuffer */
        uint32_t adcValue1 = adcBuffer[0];
        uint32_t adcValue2 = adcBuffer[1];

         /* Example: Print the ADC values (you can replace this with your own processing code) */
        printf("ADC1 Value: %lu, ADC2 Value: %lu\n", adcValue1, adcValue2);

         /* Stop the ADC conversion */
        if (HAL_ADCEx_MultiModeStop_DMA(&hadc_master) != HAL_OK)
        {
             /* Stop Error */
            Error_Handler();
        }
    }
}
uint32_t adcBuffer[2];
/* Loop for Multiple Iterations  var */
uint32_t TestLoop = 3;

int main(void)
{
    // Add your Init and config code

    /* ADC activation */
    HAL_ADC_MM_Start(&hadc_master);

    while (TestLoop != 0)
    {
       /* ADC with DMA measurement */
      if (HAL_ADC_MM_REG_StartConv_DMA(&hadc_master, (uint32_t*)adcBuffer, ADC_BUFFER_SIZE) != HAL_OK)
      {
          /* Start Error */
          Error_Handler();
      }
      /* Wait time for ADC conversion */
      HAL_Delay(5);
      TestLoop--;
    }
    /* Stop ADC */
    HAL_ADC_MM_Stop();
}

/* Error Handler */
void Error_Handler(void)
{
    while (1)
    {
       /* Stay in this loop in case of error */
    }
}

/* ADC conversion complete callback */
void HAL_ADC_REG_DataTransferCpltCallback(hal_adc_handle_t *hadc)
{
    if (hadc->Instance == ADC1)
    {
         /* Process the ADC conversion results stored in adcBuffer */
        uint32_t adcValue1 = adcBuffer[0];
        uint32_t adcValue2 = adcBuffer[1];

         /* Example: Print the ADC values (you can replace this with your own processing code) */
        printf("ADC1 Value: %lu, ADC2 Value: %lu\n", adcValue1, adcValue2);

         /* Stop the ADC conversion */
        if (HAL_ADC_MM_REG_StopConv_DMA(&hadc_master) != HAL_OK)
        {
             /* Stop Error */
            Error_Handler();
        }
    }
}

Key changes

  1. The split of the activate and start conversion in multimode DMA functions.

  2. The split of the disable and stop conversion in multimode DMA functions.